﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace StyleMVVM.View
{
	public class ValidationAdorner
	{
		public static bool GetIsEnabled(DependencyObject obj)
		{
			return (bool)obj.GetValue(IsEnabledProperty);
		}

		public static void SetIsEnabled(DependencyObject obj, bool value)
		{
			obj.SetValue(IsEnabledProperty, value);
		}

		// Using a DependencyProperty as the backing store for IsEnabled.  This enables animation, styling, binding, etc...
		public static readonly DependencyProperty IsEnabledProperty =
			DependencyProperty.RegisterAttached("IsEnabled",
			                                    typeof(bool),
			                                    typeof(ValidationAdorner),
			                                    new PropertyMetadata(false, IsEnabledChanged));

		private static void IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			FrameworkElement frameworkElement = d as FrameworkElement;

			if (frameworkElement != null)
			{
				frameworkElement.DataContextChanged -= FrameworkElementOnDataContextChanged;

				if ((bool)e.NewValue)
				{
					frameworkElement.DataContextChanged += FrameworkElementOnDataContextChanged;

					ValidationAdornerHelper helper = ValidationAdornerHelper.GetHelper(frameworkElement);

					if (helper != null)
					{
						helper.Disconnect();
					}

					if (frameworkElement.DataContext != null)
					{
						if (frameworkElement.IsLoaded)
						{
							string path = GetPropertyPath(frameworkElement);

							if (!string.IsNullOrEmpty(path))
							{
								ValidationAdornerHelper.SetHelper(frameworkElement,
								                                  new ValidationAdornerHelper(frameworkElement,
								                                                              frameworkElement.DataContext,
								                                                              path));
							}
						}
						else
						{
							frameworkElement.Loaded += FrameworkElementOnLoaded;
						}
					}
				}
			}
		}

		private static void FrameworkElementOnDataContextChanged(object sender,
		                                                         DependencyPropertyChangedEventArgs
			                                                         dependencyPropertyChangedEventArgs)
		{
			FrameworkElement frameworkElement = sender as FrameworkElement;

			if (frameworkElement != null)
			{
				ValidationAdornerHelper helper = ValidationAdornerHelper.GetHelper(frameworkElement);

				if (helper != null)
				{
					helper.Disconnect();
				}

				if (frameworkElement.DataContext != null)
				{
					frameworkElement.Loaded += FrameworkElementOnLoaded;
				}
			}
		}

		private static void FrameworkElementOnLoaded(object sender, RoutedEventArgs routedEventArgs)
		{
			FrameworkElement frameworkElement = sender as FrameworkElement;

			if (frameworkElement != null)
			{
				string path = GetPropertyPath(frameworkElement);

				ValidationAdornerHelper.SetHelper(frameworkElement,
				                                  new ValidationAdornerHelper(frameworkElement, frameworkElement.DataContext, path));
			}

			frameworkElement.Loaded -= FrameworkElementOnLoaded;
		}

		private static string GetPropertyPath(FrameworkElement frameworkElement)
		{
			string path = GetPropertyName(frameworkElement);

			if (string.IsNullOrEmpty(path))
			{
				Binding binding = null;

				if (frameworkElement is TextBox)
				{
					BindingExpression expression = BindingOperations.GetBindingExpression(frameworkElement, TextBox.TextProperty);
					binding = BindingOperations.GetBinding(frameworkElement, TextBox.TextProperty);

					bool value = BindingOperations.IsDataBound(frameworkElement, TextBox.TextProperty);
				}
				else if (frameworkElement is ComboBox)
				{
					binding = BindingOperations.GetBinding(frameworkElement, ComboBox.SelectedItemProperty);

					if (binding == null)
					{
						binding = BindingOperations.GetBinding(frameworkElement, ComboBox.SelectedValuePathProperty);
					}
				}
				else if (frameworkElement is CheckBox)
				{
					binding = BindingOperations.GetBinding(frameworkElement, CheckBox.IsCheckedProperty);
				}

				if (binding != null)
				{
					path = binding.Path.Path;
				}
			}
			return path;
		}

		public static string GetPropertyName(DependencyObject obj)
		{
			return (string)obj.GetValue(PropertyNameProperty);
		}

		public static void SetPropertyName(DependencyObject obj, string value)
		{
			obj.SetValue(PropertyNameProperty, value);
		}

		// Using a DependencyProperty as the backing store for PropertyName.  This enables animation, styling, binding, etc...
		public static readonly DependencyProperty PropertyNameProperty =
			DependencyProperty.RegisterAttached("PropertyName",
			                                    typeof(string),
			                                    typeof(ValidationAdorner),
			                                    new PropertyMetadata(null));
	}
}